package com.sinodata.bsm.center.web.action.resource;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import net.sf.json.JSONArray;
import net.sf.json.JSONObject;

import org.springframework.beans.factory.annotation.Autowired;

import com.sinodata.bsm.center.bean.RelationHelper;
import com.sinodata.bsm.center.bean.ResBean;
import com.sinodata.bsm.center.bean.ResTypeBean;
import com.sinodata.bsm.center.cache.ResGroupCache;
import com.sinodata.bsm.center.cache.ResTypeDispConfCache;
import com.sinodata.bsm.center.cache.TreeNodeSequenceCache;
import com.sinodata.bsm.center.purview.FunctionConstants;
import com.sinodata.bsm.center.purview.UserFunctionValidate;
import com.sinodata.bsm.center.service.relation.ResRelationService;
import com.sinodata.bsm.center.service.resource.ResService;
import com.sinodata.bsm.center.service.resource.ResViewService;
import com.sinodata.bsm.center.user.UserUtil;
import com.sinodata.bsm.center.util.spring.SpringContextHolder;
import com.sinodata.bsm.center.util.web.Struts2Utils;
import com.sinodata.bsm.center.web.action.BaseAction;
import com.sinodata.bsm.common.vo.RelationType;
import com.sinodata.bsm.common.vo.Res;
import com.sinodata.bsm.common.vo.ResGroup;
import com.sinodata.bsm.common.vo.ResType;
import com.sinodata.bsm.common.vo.ResTypeDispConf;
import com.sinodata.bsm.common.vo.ResView;
import com.sinodata.bsm.common.vo.ResViewRel;

public class ResFrameAction extends BaseAction<Res> {
    @Autowired
    private ResViewService resViewService;
    @Autowired
    private ResService resService;
    @Autowired
    private ResRelationService resRelationService;
    @Autowired
    private ResTypeDispConfCache resTypeDispConfCache;
    @Autowired
    private TreeNodeSequenceCache treeNodeSequenceCache;
    @Autowired
    private ResGroupCache resGroupCache;
    private String id;
    public final static int NODE_TYPE_RESOURCE = 2;
    public final static int NODE_TYPE_RESTYPE = 3;

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    @Override
    public String delete() throws Exception {

        return null;
    }

    @Override
    public String input() throws Exception {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public String list() throws Exception {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    protected void prepareModel() throws Exception {
        logger.info(this.id);
    }

    @SuppressWarnings("unchecked")
    public String initView() throws Exception {
        List results = new ArrayList();
        try {
            ResView[] views = resViewService.findAll();
            Map<Long, Long> initResMap = new HashMap<Long, Long>();
            List<ResView> purview = new ArrayList<ResView>();
            for (ResView view : views) {
                if (!UserFunctionValidate.viewFunctionValidate(view.getId(), FunctionConstants.VIEW_VIEW)) {
                    continue;
                }
                purview.add(view);
                List<Long> resList = UserFunctionValidate.getResIdListForUser(FunctionConstants.VIEW_RES);
                if (resList == null || resList.size() == 0) {
                    continue;
                }

                List<Long> rootList = resViewService.findChildByViewId(view.getId(), resList);
                if (rootList != null && rootList.size() > 0) {
                    initResMap.put(view.getId(), rootList.get(0));
                }
                List<ResGroup> groups = resGroupCache.findByResViewId(view.getId());
                if (groups != null && groups.size() > 0) {
                    initResMap.put(view.getId(), groups.get(0).getId());
                }
            }
            results.add(purview.toArray());
            Long lastViewId = (Long) request.getSession().getAttribute("lastView");
            if (lastViewId == null) {
                lastViewId = purview.get(0).getId();
            }
            request.getSession().setAttribute("lastView", lastViewId);
            ResView lastView = resViewService.get(lastViewId);

            results.add(lastView == null ? purview.get(0) : lastView);
            String lastResMenu = (String) request.getSession().getAttribute("lastResMenu");
            if (lastResMenu == null) {
                lastResMenu = "res_info";
                request.getSession().setAttribute("lastResMenu", lastResMenu);
            }
            results.add(lastResMenu);
            results.add(initResMap);
            Map<String, List<String>> map = (Map<String, List<String>>) request.getSession().getAttribute("nodeTrace");
            if (map != null) {
                results.add(map);
            } else {
                results.add(new HashMap<String, List<String>>(0));
            }
        } catch (Exception ex) {
            logger.error("error init resView", ex);
        }
        Struts2Utils.renderJson(results);
        return null;
    }

    public String saveCurrentMenu() throws Exception {
        String menuId = request.getParameter("menuId");
        String type = request.getParameter("type");
        if (type.equals("2")) {

            request.getSession().setAttribute("lastResMenu", menuId);
        } else {
            request.getSession().setAttribute("lastResTypeMenu", menuId);
        }
        return null;
    }

    private Set<Long> findRelationTypeIds() {

        Set<RelationType> relationTypes = resRelationService.getSelfAndSubRelationType();
        Set<Long> relationTypesIds = new HashSet<Long>();
        for (RelationType type : relationTypes) {
            relationTypesIds.add(type.getId().longValue());
        }
        return relationTypesIds;
    }

    public String customizeTree() throws Exception {
        try {

            String nodeId = id;
            Set<Long> relationTypesIds = findRelationTypeIds();
            if (nodeId == null) {

                List<Long> rootList = new ArrayList<Long>();
                String startId = request.getParameter("startId");
                rootList.add(Long.parseLong(startId));
                this.statusMap = new HashMap<String, Integer>();
                JSONArray jsonArray = new JSONArray();
                for (Long rootId : rootList) {
                    ResBean resBean = ResBean.get(rootId.longValue());
                    if (resBean != null) {
                        JSONObject rootJson = genResNode(resBean.res(), 0L, relationTypesIds);
                        loadLevel(rootJson, 2, 1, relationTypesIds);
                        jsonArray.add(rootJson);
                    }
                }
                Struts2Utils.renderText(jsonArray.toString());
            } else {
                this.statusMap = new HashMap<String, Integer>();
                String[] idArray = this.id.split("[|]");

                JSONArray children = loadChildNode(Long.parseLong(idArray[1]), relationTypesIds);
                sortChildNodeSequence(this.id, children);
                Struts2Utils.renderText(children.toString());
            }
        } catch (Exception ex) {
            logger.error("error genernate customize tree", ex);
        }
        return null;
    }

    public String viewTree() throws Exception {
        try {
            // List<Long> resList = UserFunctionValidate
            // .getResIdListForUser(FunctionConstants.VIEW_RES);
            String viewId = request.getParameter("viewId");
            String nodeId = id;
            Set<Long> relationTypesIds = findRelationTypeIds();
            if (nodeId == null) {
                ResViewService service = SpringContextHolder.getBean(ResViewService.class);
                ResView view = service.get(Long.parseLong(viewId));

                int expandLevel = view.getExpandLevel() > 2 ? 2 : view.getExpandLevel();
                List<Long> rootList = new ArrayList<Long>();
                String userId = UserUtil.getInstance().getCurrentUserId();
                if (UserUtil.getInstance().isSysAdmin(userId)) {
                    List<ResViewRel> viewRelList = resViewService.getResViewRelByViewId(Long.parseLong(viewId));
                    if (viewRelList != null) {
                        for (ResViewRel rel : viewRelList) {
                            rootList.add(rel.getResId().longValue());
                        }
                    }
                } else {
                    // 不是
                    List<Long> resList = UserFunctionValidate.getResIdListForUser(FunctionConstants.VIEW_RES);
                    rootList = resViewService.findChildByViewId(Long.parseLong(viewId), resList);
                }
                Map<String, Integer> smap = new HashMap<String, Integer>();
                request.getSession().setAttribute("viewTree#" + viewId, smap);
                this.statusMap = smap;
                JSONArray jsonArray = new JSONArray();
                Map<String, List<String>> map = (Map<String, List<String>>) request.getSession().getAttribute("nodeTrace");
                if (map == null) {
                    map = new HashMap<String, List<String>>();
                    request.getSession().setAttribute("nodeTrace", map);
                }
                List<String> nodeTrace = map.get(viewId);
                if (nodeTrace == null) {
                    nodeTrace = new ArrayList<String>(0);
                }
                for (Long rootId : rootList) {
                    ResBean resBean = ResBean.get(rootId.longValue());
                    if (resBean != null) {
                        JSONObject rootJson = genResNode(resBean.res(), 0L, relationTypesIds);
                        String ids = rootJson.getString("id");

                        if (nodeTrace.contains(ids)) {
                            loadLevel2(rootJson, expandLevel, 1, nodeTrace, relationTypesIds);
                        } else {
                            loadLevel(rootJson, expandLevel, 1, relationTypesIds);
                        }
                        jsonArray.add(rootJson);
                    }
                }

                Struts2Utils.renderText(jsonArray.toString());

            } else {
                this.statusMap = (Map<String, Integer>) request.getSession().getAttribute("viewTree#" + viewId);
                String[] idArray = this.id.split("[|]");
                JSONArray children = loadChildNode(Long.parseLong(idArray[1]), relationTypesIds);
                sortChildNodeSequence(this.id, children);
                Struts2Utils.renderText(children.toString());
            }
        } catch (Exception ex) {
            logger.error("error genernate view tree", ex);
        }
        return null;
    }

    private void sortChildNodeSequence(String parentNodeId, JSONArray children) {
        if (treeNodeSequenceCache.hasNodeConf(parentNodeId)) {
            String[] array = treeNodeSequenceCache.get(parentNodeId).getChildNodeIds().split("[$]");
            TreeNodeCompare compare = new TreeNodeCompare(array);
            Collections.sort(children, compare);
        }
    }

    private void loadLevel2(JSONObject resjson, int expandLevel, int level, List<String> nodeTrace, Set<Long> relationTypesIds) {
        try {

            if (!nodeTrace.contains(resjson.getString("id"))) {
                if (expandLevel == level) {
                    return;
                }
            } else {
                if (level >= nodeTrace.size() && expandLevel == level) {
                    return;
                }
            }
            if (level < expandLevel) {
                resjson.element("open", true);
            } else {
                if (nodeTrace.contains(resjson.getString("id"))) {
                    resjson.element("open", true);
                }
            }
            level++;
            String[] idArr = resjson.getString("id").split("[|]");
            JSONArray children = loadChildNode(Long.parseLong(idArr[1]), relationTypesIds);
            sortChildNodeSequence(resjson.getString("id"), children);
            resjson.element("children", children);
            for (int i = 0; i < children.size(); i++) {
                JSONObject obj = children.getJSONObject(i);
                idArr = obj.getString("id").split("[|]");
                if (idArr[0].equals("3")) {
                    if (level < expandLevel) {
                        obj.element("open", true);
                    } else {
                        if (nodeTrace.contains(obj.getString("id"))) {
                            obj.element("open", true);
                        }
                    }
                    JSONArray resJsons = obj.getJSONArray("children");
                    for (int k = 0; k < resJsons.size(); k++) {
                        JSONObject res = resJsons.getJSONObject(k);
                        loadLevel2(res, expandLevel, level, nodeTrace, relationTypesIds);
                    }
                } else {
                    loadLevel2(obj, expandLevel, level, nodeTrace, relationTypesIds);
                }
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }

    }

    private void loadLevel(JSONObject resjson, int expandLevel, int level, Set<Long> relationTypesIds) {
        try {

            if (level >= expandLevel) {
                return;
            }
            resjson.element("open", true);
            level++;
            String[] idArr = resjson.getString("id").split("[|]");
            JSONArray children = loadChildNode(Long.parseLong(idArr[1]), relationTypesIds);
            sortChildNodeSequence(resjson.getString("id"), children);
            resjson.element("children", children);
            for (int i = 0; i < children.size(); i++) {
                JSONObject obj = children.getJSONObject(i);
                idArr = obj.getString("id").split("[|]");
                if (idArr[0].equals("3")) {

                    obj.element("open", true);

                    JSONArray resJsons = obj.getJSONArray("children");
                    for (int k = 0; k < resJsons.size(); k++) {
                        JSONObject res = resJsons.getJSONObject(k);
                        loadLevel(res, expandLevel, level, relationTypesIds);
                    }
                } else {
                    loadLevel(obj, expandLevel, level, relationTypesIds);
                }
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    private JSONArray loadChildNode(Long parentResId, Set<Long> relationTypesIds) {
        List<List<ResBean>> types = children(parentResId);
        JSONArray jsonArray = new JSONArray();
        for (int i = 0; i < types.size(); i++) {
            List<ResBean> type = types.get(i);
            if (type.size() == 1) {
                JSONObject childRes = genResNode(type.get(0).res(), parentResId, relationTypesIds);
                jsonArray.add(childRes);
            } else {
                JSONArray childArray = new JSONArray();
                int maxStatus = 0;
                int pausedSize = 0;
                for (int j = 0; j < type.size(); j++) {
                    Res cRes = type.get(j).res();
                    if (cRes.getHealthStatus() > maxStatus) {
                        maxStatus = cRes.getHealthStatus();
                    }
                    if (cRes.getPaused() == 1) {
                        pausedSize++;
                    }
                    JSONObject childRes = genResNode(cRes, parentResId, relationTypesIds);
                    childArray.add(childRes);
                }
                ResTypeDispConf conf = resTypeDispConfCache.find(parentResId, type.get(0).res().getResTypeId());
                boolean showTypeNode = true;
                String typename = null;
                if (conf != null) {
                    showTypeNode = conf.getIsDisp() == 1 ? true : false;
                    typename = conf.getDispName() == null ? null : conf.getDispName();
                }
                if (showTypeNode) {
                    ResTypeBean resTypeBean = type.get(0).type();
                    JSONObject typeNode = genResTypeNode(resTypeBean.resType(), parentResId);
                    if (typename != null) {
                        typeNode.element("name", typename);
                    }
                    int status = type.size() == pausedSize ? 0 : maxStatus;
                    typeNode.element("iconSkin", "type" + status);
                    statusMap.put("3|" + resTypeBean.resType().getId() + "|" + parentResId, status);
                    typeNode.element("children", childArray);
                    jsonArray.add(typeNode);
                } else {
                    jsonArray.addAll(childArray);
                }
            }
        }

        return jsonArray;
    }

    private Map<String, Integer> statusMap = null;

    public String refreshTreeNode() {
        String viewId = request.getParameter("viewId");
        Map<String, Integer> map = (Map<String, Integer>) request.getSession().getAttribute("viewTree#" + viewId);
        Iterator<String> it = map.keySet().iterator();
        List<Object[]> statusList = new ArrayList<Object[]>();
        while (it.hasNext()) {
            String key = it.next();
            String[] idArray = key.split("[|]");
            if (idArray[0].equals("2")) {
                long resId = Long.parseLong(idArray[1]);
                ResBean resbean = ResBean.get(resId);
                if (resbean == null) {
                    continue;
                }
                Res res = resbean.res();
                int currentStatus = res.getPaused() == 1 ? 0 : res.getHealthStatus();
                int oldStatus = map.get(key);

                if (oldStatus != currentStatus) {
                    Object[] objs = new Object[2];
                    objs[0] = key;
                    objs[1] = "res" + currentStatus;
                    statusList.add(objs);
                    map.put(key, currentStatus);
                }
            } else {

                List<ResBean> children = resService.findChildren(Long.parseLong(idArray[2]), Long.parseLong(idArray[1]));
                int maxStatus = 0;
                int pausedSize = 0;
                for (int i = 0; i < children.size(); i++) {
                    Res cRes = children.get(i).res();
                    if (cRes.getHealthStatus() > maxStatus) {
                        maxStatus = cRes.getHealthStatus();
                    }

                    if (cRes.getPaused() == 1) {
                        pausedSize++;
                    }
                }
                int currentStatus = children.size() == pausedSize ? 0 : maxStatus;
                int oldStatus = map.get(key);
                if (oldStatus != currentStatus) {
                    Object[] objs = new Object[2];
                    objs[0] = key;
                    objs[1] = "res" + currentStatus;
                    statusList.add(objs);
                    map.put(key, currentStatus);
                }
            }
        }
        Struts2Utils.renderJson(statusList);
        return null;
    }

    private JSONObject genResNode(Res res, Long parentResId, Set<Long> relationTypesIds) {
        JSONObject json = new JSONObject();
        json.element("id", "2|" + res.getId() + "|" + parentResId);
        json.element("name", res.getName());

        int status = res.getPaused() == 1 ? 0 : res.getHealthStatus();
        json.element("iconSkin", "res" + status);
        statusMap.put("2|" + res.getId() + "|" + parentResId, status);
        json.element("isParent", resRelationService.hasChild(res.getId(), relationTypesIds));
        return json;
    }

    private JSONObject genResTypeNode(ResType resType, Long resId) {
        JSONObject json = new JSONObject();
        json.element("id", "3|" + resType.getId() + "|" + resId);
        json.element("name", resType.getName());
        json.element("isParent", true);
        return json;
    }

    private JSONObject genResViewNode(ResView view) {
        JSONObject json = new JSONObject();
        json.element("id", "1|" + view.getId() + "|0");
        json.element("name", view.getName());
        json.element("open", true);
        json.element("nocheck", true);
        return json;
    }

    private List<List<ResBean>> children(Long parentResId) {
        List<ResBean> children = RelationHelper.children(parentResId);
        List<List<ResBean>> types = new ArrayList<List<ResBean>>();
        for (ResBean child : children) {
            List<ResBean> type = null;
            for (int j = 0; j < types.size(); j++) {
                if (types.get(j).get(0).res().getResTypeId().longValue() == child.res().getResTypeId().longValue()) {
                    type = types.get(j);
                    break;
                }
            }
            if (type == null) {
                type = new ArrayList<ResBean>();
                types.add(type);
            }
            type.add(child);
        }
        return types;
    }

    public String resViewTree() throws Exception {
        ResView[] viewList = resViewService.findAll();

        Map<String, Integer> smap = new HashMap<String, Integer>();
        Set<Long> relationTypesIds = findRelationTypeIds();
        this.statusMap = smap;
        String userId = UserUtil.getInstance().getCurrentUserId();
        if (id == null) {
            JSONArray jsonArray = new JSONArray();
            for (ResView view : viewList) {
                // /////////////////////////////////////////////////////////////////////////////////
                List<Long> rootList = new ArrayList<Long>();
                if (UserUtil.getInstance().isSysAdmin(userId)) {
                    List<ResViewRel> viewRelList = resViewService.getResViewRelByViewId(view.getId());
                    if (viewRelList != null) {
                        for (ResViewRel rel : viewRelList) {
                            rootList.add(rel.getResId().longValue());
                        }
                    }
                } else {
                    // 不是
                    List<Long> resList = UserFunctionValidate.getResIdListForUser(FunctionConstants.VIEW_RES);
                    rootList = resViewService.findChildByViewId(view.getId(), resList);
                }
                // ////////////////////////////////////////////////////////////////////////////////
                if (rootList.size() > 0) {
                    JSONObject json = genResViewNode(view);
                    JSONArray cArray = new JSONArray();
                    for (Long resId : rootList) {
                        if (ResBean.get(resId) == null || ResBean.get(resId).res() == null)
                            continue;
                        JSONObject rootJson = genResNode(ResBean.get(resId).res(), 0L, relationTypesIds);
                        loadLevel(rootJson, 1, 1, relationTypesIds);
                        cArray.add(rootJson);

                    }
                    json.element("children", cArray);
                    jsonArray.add(json);
                }

            }
            Struts2Utils.renderText(jsonArray.toString());
        } else {
            String[] idArray = this.id.split("[|]");
            JSONArray children = loadChildNode(Long.parseLong(idArray[1]), relationTypesIds);
            sortChildNodeSequence(this.id, children);
            Struts2Utils.renderText(children.toString());
        }

        return null;
    }

    public String saveCurrentView() throws Exception {
        String viewId = request.getParameter("viewId");

        request.getSession().setAttribute("lastView", Long.parseLong(viewId));

        return null;
    }

    public String saveNodeTrace() throws Exception {
        String nodes = request.getParameter("nodes");
        String viewId = request.getParameter("viewId");
        Map<String, List<String>> map = (Map<String, List<String>>) request.getSession().getAttribute("nodeTrace");
        if (map == null) {
            map = new HashMap<String, List<String>>();
        }
        List<String> list = new ArrayList<String>();
        String[] nodeArr = nodes.split(",");
        for (int i = nodeArr.length - 1; i >= 0; i--) {
            list.add(nodeArr[i]);
        }
        map.put(viewId, list);
        return null;
    }

    @Override
    public String execute() throws Exception {
        ResView[] views = resViewService.findAll();

        request.setAttribute("resViews", views);
        return SUCCESS;
    }

    @Override
    public String save() throws Exception {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public Res getModel() {
        // TODO Auto-generated method stub
        return null;
    }

    private class TreeNodeCompare implements Comparator {
        private final Map<String, Integer> nodeMap = new HashMap<String, Integer>();

        TreeNodeCompare(String[] nodeIds) {
            for (int i = 0; i < nodeIds.length; i++) {
                nodeMap.put(nodeIds[i], i);
            }
        }

        @Override
        public int compare(Object o1, Object o2) {
            String nodeId1 = ((JSONObject) o1).getString("id");
            String nodeId2 = ((JSONObject) o2).getString("id");
            int i1 = nodeMap.containsKey(nodeId1) ? nodeMap.get(nodeId1) : Integer.MAX_VALUE;
            int i2 = nodeMap.containsKey(nodeId2) ? nodeMap.get(nodeId2) : Integer.MAX_VALUE;
            return i1 - i2;
        }
    }

}
